#include <jni.h>
#include <string>
#include <android/log.h>

extern "C" {
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>
}
extern "C" JNIEXPORT jstring JNICALL
Java_com_xia_ndk_1audio_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT void JNICALL
Java_com_xia_ndk_1audio_MainActivity_playMusic(JNIEnv *env, jobject thiz, jstring input,
                                               jstring output) {
    // TODO: implement playMusic()
    const char *inputStr = env->GetStringUTFChars(input, NULL);
    const char *outputStr = env->GetStringUTFChars(output, NULL);

    // TODO xia chen hui 2020/6/16 22:23 1.打开网络
    avformat_network_init();
    // TODO xia chen hui 2020/6/16 22:24 2.媒体上下文
    AVFormatContext *avFormatContext = avformat_alloc_context();
    // TODO xia chen hui 2020/6/16 22:24 3. 打开文件
    int ret = avformat_open_input(&avFormatContext, inputStr, NULL, NULL);
    __android_log_print(ANDROID_LOG_DEBUG, "MyPlayer===========",
                        "prepare_avformat_open_input_____:%s", av_err2str(ret));
    if (ret < 0) {
        return;
    }
    // TODO xia chen hui 2020/6/16 22:26 4.获取音频文件信息，如果不能，就终止
    ret = avformat_find_stream_info(avFormatContext, NULL);
    if (ret < 0) {
        return;
    }
    // TODO xia chen hui 2020/6/16 22:27 5. 筛选音频流 ,为了记录下标
    int audioIndex = -1;
    for (int i = 0; i < avFormatContext->nb_streams; ++i) {
        if (avFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
            audioIndex = i;
            break;
        }
    }
    // TODO xia chen hui 2020/6/16 22:29 6.拿到解码器，通过解码器id 获取解码器
    // 解码器参数，为了获取解码器ID
    AVCodecParameters *parameters = avFormatContext->streams[audioIndex]->codecpar;
    //解码器
    AVCodec *avCodec = avcodec_find_decoder(parameters->codec_id);
    // TODO xia chen hui 2020/6/16 22:32 7. 解码器山下文
    AVCodecContext *avCodecContext = avcodec_alloc_context3(avCodec);
    //解码器参数设置解码器上下文,进行关联
    avcodec_parameters_to_context(avCodecContext, parameters);
    // TODO xia chen hui 2020/6/16 22:33 8.打开解码器
    avcodec_open2(avCodecContext, avCodec, NULL);
    // TODO xia chen hui 2020/6/16 22:34 9.拿到编码数据，压缩数据 AAC
    AVPacket *avPacket = av_packet_alloc();

    // TODO xia chen hui 2020/6/16 22:45 重采样 （接步骤12）
    //输入信息可以不同，输出要一致
    SwrContext *swrContext = swr_alloc();
    //输入的信息(采样格式),媒体是什么就获取什么
    AVSampleFormat in_sample_fmt = avCodecContext->sample_fmt;
    //输入的采样率
    int in_sample_rate = avCodecContext->sample_rate;
    //输入的通道数，声道布局
    int in_channel_layout = avCodecContext->channel_layout;
    //输出的信息
    AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;
    //因为知道是mp3  所以设置未44100
    int out_sample_rate = 44100;
    //双声道
    int out_channel_layout = AV_CH_LAYOUT_STEREO;
    //真正的转换
    swr_alloc_set_opts(swrContext, out_channel_layout, out_sample_fmt, out_sample_rate //输出
            , in_channel_layout, in_sample_fmt, in_sample_rate //输入
            , 0, NULL);
    //处理细节，简单初始化，否则播放的时候会有滋滋的声音
    swr_init(swrContext);
    //定义输出缓冲区 ,因为是立体声 双声道，所以2 * 44100
    uint8_t *out_buffer = static_cast<uint8_t *>(av_malloc(2 * 44100));
    //输出的文件
    FILE *pcm_file = fopen(outputStr, "wb");



    // TODO xia chen hui 2020/6/16 22:36 10. 拿到原始数据
    while (av_read_frame(avFormatContext, avPacket) >= 0) {
        //需要取哪些数据
        avcodec_send_packet(avCodecContext, avPacket);
        //拿到原始数据
        AVFrame *avFrame = av_frame_alloc();
        // TODO xia chen hui 2020/6/16 22:39 11.取出真正的原始数据
        ret = avcodec_receive_frame(avCodecContext, avFrame);
        //这时候 avFrame有原始的PCM数据了
        //拿到关键帧
        if (ret == AVERROR(EAGAIN)) {
            continue; //没有遇到关键帧，再次重试
        } else if (ret < 0) {
            return;//解码器已经完成了
        }
        //为了健壮性
        if (avPacket->stream_index != audioIndex) {
            continue; //非音频 ，重试
        }
        // TODO xia chen hui 2020/6/16 22:43 12 真正解码，音视频重采样
        //声卡要求 音频输出格式要统一（采样率统一，通道数统一等）
        //把PCM原始音频数据 ，统一处理,建立统一格式
        swr_convert(swrContext,
                //输出相关
                    &out_buffer,//输出缓冲区
                    2 * 44100,
                //输入相关
                    (const uint8_t **) (avFrame->data), //原始数据
                    avFrame->nb_samples //输入的流
        );
        // TODO xia chen hui 2020/6/16 23:00 13. 写入文件
        int out_buffer_size = av_samples_get_buffer_size(NULL, 2, avFrame->nb_samples,
                                                         out_sample_fmt, 1);
        fwrite(out_buffer, 1, out_buffer_size, pcm_file);
        //释放
        if (avFrame) {
            av_frame_free(&avFrame);
            avFrame = 0;
        }
    }


}